home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’94
/
[√] Distribution Restricted!
/
Steve Sisak
/
TMFutures
/
AEThreads.c
next >
Wrap
Text File
|
1994-06-26
|
6KB
|
254 lines
/*
File: AEThreads.c
Contains: xxx put contents here xxx
Written by: xxx put writers here xxx
Copyright: © 1994 Steve Sisak, all rights reserved.
Change History (most recent first):
*/
#ifndef __AETHREADS__
#include "AEThreads.h"
#endif
#ifndef __UFAILURE__
#include "UFailure.h"
#endif
#ifndef __ERRORS__
#include <Errors.h>
#endif
#include <AppleEvents.h>
typedef struct AEThreadDesc AEThreadDesc;
typedef struct AEThreadParam AEThreadParam;
struct AEThreadDesc // Kept in the OS refcon
{
AEEventHandlerUPP handler; // The real handler
long refcon; // The real refcon
Size stackSize; // Stack size for handling event
ThreadOptions options; // Thread options for event
ThreadID holder; // used as a semaphore
};
struct AEThreadParam // Used in spawning
{
const AppleEvent* event;
AppleEvent* reply;
AEThreadDesc* desc;
ThreadID thread;
OSErr result;
};
pascal void SwapTopHandler(ThreadID threadBeingSwitched, void *switchProcParam);
pascal OSErr SpawnAEThread(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
pascal long AEThread(AEThreadParam* parms);
AEEventHandlerUPP gSpawnAEThreadUPP = nil;
#pragma segment foobar
pascal OSErr AEInstallThreadedEventHandler(
AEEventClass theAEEventClass,
AEEventID theAEEventID,
AEEventHandlerProcPtr proc,
long handlerRefcon,
ThreadOptions options,
Size stacksize)
{
AEThreadDesc* desc = (AEThreadDesc*) NewPtr(sizeof(AEThreadDesc));
OSErr err = MemError();
if (gSpawnAEThreadUPP == nil)
{
gSpawnAEThreadUPP = NewAEEventHandlerProc(SpawnAEThread);
}
if (err == noErr)
{
desc->handler = NewAEEventHandlerProc(proc);
desc->refcon = handlerRefcon;
desc->stackSize = stacksize;
desc->options = options;
desc->holder = kNoThreadID;
err = AEInstallEventHandler(theAEEventClass, theAEEventID, gSpawnAEThreadUPP, (long) desc, false);
}
return err;
}
#pragma segment AEThread
pascal void AEThreadTerminator(ThreadID threadTerminated, void *terminationProcParam);
pascal void AEThreadTerminator(ThreadID threadTerminated, void *terminationProcParam)
{
FailInfo fi;
FailInfoPtr oldTopHandler = gTopHandler; // save current handler
FailInfoPtr newTopHandler = * (FailInfoPtr*) terminationProcParam;
Debugger();
if (newTopHandler != nil)
{
gTopHandler = newTopHandler; // point to top of thread's handlers
while (newTopHandler->nextInfo != nil) // find bottom handler
{
newTopHandler = newTopHandler->nextInfo;
}
newTopHandler->nextInfo = &fi; // now splice fi in below it
if (setjmp(fi.savedState) == 0)
{
Failure(userCanceledErr, 0); // and trip the handlers
}
gTopHandler = oldTopHandler; // restore top handler
}
}
pascal void SwapTopHandler(ThreadID threadBeingSwitched, void *switchProcParam)
{
FailInfoPtr* save = (FailInfoPtr*) switchProcParam;
FailInfoPtr temp = *save;
*save = gTopHandler;
gTopHandler = temp;
}
pascal long AEThread(AEThreadParam* parms)
{
AppleEvent event; // Original parameters we care about
AppleEvent reply;
AEThreadDesc* desc;
FailInfoPtr myTopHandler; // Used to save the inactive failure handler
FailInfo fi;
OSErr err;
event = *parms->event; // copy these into our own stack frame
reply = *parms->reply;
desc = parms->desc;
myTopHandler = gTopHandler; // Save global failure handler
gTopHandler = nil; // don't let failures propagate outside
Try (fi)
{
// We need to make sure that the gTopHandler switches in and out with our thread
FailOSErr(SetThreadSwitcher(kCurrentThreadID, SwapTopHandler, &myTopHandler, true));
FailOSErr(SetThreadSwitcher(kCurrentThreadID, SwapTopHandler, &myTopHandler, false));
// FailOSErr(SetThreadTerminator(kCurrentThreadID, AEThreadTerminator, &myTopHandler));
FailOSErr(AESuspendTheCurrentEvent(&event));
parms->result = noErr; // Let caller know we're ready
Success(&fi);
}
else
{
parms->result = fi.error;
return nil;
}
// At this point, we need to let our caller return
while (desc->holder != kNoThreadID)
{
YieldToThread(desc->holder);
}
// We are now on our own
Try (fi)
{
FailOSErr(CallAEEventHandlerProc(desc->handler, &event, &reply, desc->refcon));
Success(&fi);
}
else
{
// Since the event was suspended, we need to stuff the error code ourselves
// note that there's not much we can do about reporting errors beyond here
err = AEPutAttributePtr(&reply, keyErrorNumber, typeShortInteger, &fi.error, sizeof(fi.error));
#if qDebug
if (err)
ProgramBreak("\pAEPutAttributePtr failed installing error code - very bad");
#endif
}
err = AEResumeTheCurrentEvent(&event, &reply, kAENoDispatch, 0); // This had better work
#if qDebug
if (err)
ProgramBreak("\pAEResumeTheCurrentEvent failed - very bad");
#endif
gTopHandler = myTopHandler; // Restore global failure handler
myTopHandler = nil; // Keep terminator from firing handlers
return fi.error;
}
#pragma segment Spawn
pascal OSErr SpawnAEThread(const AppleEvent *event, AppleEvent *reply, long handlerRefcon)
{
AEThreadParam param;
param.event = event;
param.reply = reply;
param.desc = (AEThreadDesc*) handlerRefcon;
param.thread = kNoThreadID;
if (!param.desc)
{
param.result = paramErr;
}
else
{
while (param.desc->holder != kNoThreadID) // make sure no-one else is trying to start a handler
{
YieldToAnyThread();
}
if ((param.result = GetCurrentThread(¶m.desc->holder)) == noErr) // Grab the semaphore
{
param.result = NewThread(kCooperativeThread,
(ThreadEntryProcPtr) &AEThread,
¶m,
param.desc->stackSize,
param.desc->options,
nil,
¶m.thread);
if (param.result == noErr)
{
param.result = 1;
do
{
YieldToThread(param.thread);
}
while (param.result == 1); // Wait for thread to pick up parameters
}
}
param.desc->holder = kNoThreadID; // release any claims we have
}
return param.result;
}